package org.btik.lightdev.dev;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.btik.context.thread.SystemControlAble;
import org.btik.light.tool.ByteUtil;

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;

/**
 * 供局域网使用,发起组播，供设备发现
 *
 * @author lustre
 * @since 2023/3/8 23:22
 */
public class ServerInfoPusher extends Thread implements SystemControlAble {
    private final Log log = LogFactory.getLog(ServerInfoPusher.class);
    private boolean runFlag = true;

    private DatagramSocket multicastSocket;

    private String multicastGroup;

    private byte[] topic;

    private byte[] clientTopic;

    private int multicastPort;

    /**
     * 本机为热点时，组播大概率无法走这个热点，这个的端口用于接收下位机的消息
     */
    private int asGatewayPort;

    private final byte[] lock = new byte[0];

    public void setEnable(boolean enable) {
        // 仅供start之前调用
        if (isAlive()) {
            return;
        }
        this.runFlag = enable;
    }

    @Override
    public synchronized void start() {
        if (!runFlag) {
            log.warn("discover is disable");
            return;
        }
        super.start();
    }

    @Override
    public void run() {
        log.info("ServerInfoPusher start");
        DatagramPacket lightServerTopic = new DatagramPacket(topic, topic.length);
        lightServerTopic.setPort(multicastPort);
        InetAddress multicastGroupAddr;
        try {
            multicastSocket = new DatagramSocket(asGatewayPort);
            multicastSocket.setSoTimeout(100);
            multicastGroupAddr = InetAddress.getByName(multicastGroup);
            lightServerTopic.setAddress(multicastGroupAddr);
        } catch (SocketException | UnknownHostException e) {
            log.info(e.getMessage(), e);
            shutdown(e.getMessage());
            return;
        }
        DatagramPacket clientInfo = new DatagramPacket(new byte[32], 32);
        while (runFlag) {
            try {
                multicastSocket.send(lightServerTopic);
                synchronized (lock) {
                    lock.wait(600);
                }
                // 尝试读取客户的往热点发的包如果本机是热点的话
                if(timeReceive(multicastSocket, clientInfo)){
                    int length = clientInfo.getLength();
                    if (length < clientTopic.length) {
                        clientInfo.setLength(0);
                        continue;
                    }
                    // 比较收到消息是否客户端topic
                    if(!ByteUtil.equals(clientInfo.getData(), clientInfo.getOffset(), clientTopic,0 ,clientTopic.length)){
                        clientInfo.setLength(0);
                        continue;
                    }
                    // 相对之后把 light-server 发给对端
                    try {
                        lightServerTopic.setAddress(clientInfo.getAddress());
                        lightServerTopic.setPort(clientInfo.getPort());
                        multicastSocket.send(lightServerTopic);
                    }finally {
                        // 发送后 把包地址改回组播
                        lightServerTopic.setPort(multicastPort);
                        lightServerTopic.setAddress(multicastGroupAddr);
                    }
                }
            } catch (IOException | InterruptedException e) {
                log.info(e.getMessage());
                if (log.isDebugEnabled()) {
                    log.debug("", e);
                }
            }

        }
    }

    private static boolean timeReceive(DatagramSocket udpSock, DatagramPacket clientMsg) throws IOException {
        try {
            udpSock.receive(clientMsg);
            return true;
        } catch (IOException e) {
            if (e instanceof SocketTimeoutException) {
                return false;
            }
            throw e;
        }
    }


    @Override
    public void shutdown(String msg) {
        runFlag = false;
        try {
            multicastSocket.close();
            synchronized (lock) {
                lock.notify();
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    public void setMulticastGroup(String multicastGroup) {
        this.multicastGroup = multicastGroup;

    }

    public void setTopic(String topic) {
        this.topic = topic.getBytes(StandardCharsets.UTF_8);
    }

    public void setMulticastPort(int multicastPort) {
        this.multicastPort = multicastPort;
    }


    public void setClientTopic(String clientTopic) {
        this.clientTopic = clientTopic.getBytes(StandardCharsets.UTF_8);
    }


    public void setAsGatewayPort(int asGatewayPort) {
        this.asGatewayPort = asGatewayPort;
    }

    public ServerInfoPusher() {
        super("ServerInfoPusher");
    }


}
